www.gusucode.com > VC 模范QQ做的一个界面-源码程序 > VC 模范QQ做的一个界面-源码程序/code/MyQQ/MagneticClass.cpp

    //Download by http://www.NewXing.com
// MagneticClass.cpp: implementation of the CMagneticClass class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MyQQ.h"
#include "MagneticClass.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CMagneticClass::CMagneticClass()
	: m_bLeftButtonDown(FALSE)
	, min_deltaX(800)
	, min_deltaY(600)
	, MagneticDistance(15)
{
	InitializeCriticalSection(&m_cs);
	//初始化主窗口信息结构,由于主窗口只有一个,所以只需一个节点就够了
	pMainWinInfo=new WinInfoStrt;

	//初始MovingWindow链表			
	pMovingWinChainHead=new WinInfoStrt;
	pMovingWinChainLast=pMovingWinChainHead;
	pMovingWinChainCur=pMovingWinChainHead;
	pMovingWinChainLast->nextPt=NULL;

	//初始化StandingWindow链表		
	pStandingWinChainHead=new WinInfoStrt;
	pStandingWinChainLast=pStandingWinChainHead;
	pStandingWinChainCur=pStandingWinChainHead;
	pStandingWinChainLast->nextPt=NULL;
}

CMagneticClass::~CMagneticClass()
{

}

CMagneticClass::SetMainWinInfo(HWND hwnd)
{
	RECT rc;
	GetWindowRect(hwnd,&rc);
	pMainWinInfo->hwnd = hwnd;
	pMainWinInfo->rc   = rc;
	pMainWinInfo->nextPt = NULL;

}

//当一个子窗口初次显示,或由不可见的状态变为可见的状态时,需要调用此函数一次
//此函数将句柄为hwnd的窗口的信息作为一个新的节点添加到StandingWindowChain中
CMagneticClass::AddAChildWindowInfo(HWND hwnd)
{
	RECT rc;
	GetWindowRect(hwnd, &rc);
	pStandingWinChainLast->nextPt = new WinInfoStrt;
	pStandingWinChainLast		  = pStandingWinChainLast->nextPt;	
	pStandingWinChainLast->hwnd	  = hwnd;
	pStandingWinChainLast->rc	  = rc;	
	pStandingWinChainLast->nextPt = NULL;
}

int CMagneticClass::DeleteAChildWindowInfo(HWND hwnd)
{
	int DoneCode = DEL_FAILED;   //先假设删除失败
	WinInfoStrt *PrePtr, *CurPtr;

	//先在Moving window 链表中查找, 若找到则删除它并设置done标记为true;
	PrePtr = pMovingWinChainHead; 
	CurPtr = pMovingWinChainHead->nextPt;
	while(CurPtr != NULL)
	{
		if(CurPtr->hwnd == hwnd)
		{
			PrePtr->nextPt = CurPtr->nextPt;
			delete CurPtr;
			DoneCode = DEL_IN_MOVING_CHAIN;  //
			break;
		}
		else
		{
			PrePtr = CurPtr;
			CurPtr = CurPtr->nextPt;
		}
	}

	//如果被删除的是最后一个节点,则将指针pMovingWinChainLast
	//改指向前一个节点
	if(CurPtr==pMovingWinChainLast)
		pMovingWinChainLast=PrePtr;

	//若在Moving window 链表中没找到,则继续在 Standing window 链表中查找
	if(DoneCode != DEL_IN_MOVING_CHAIN)
	{
		PrePtr = pStandingWinChainHead; 
		CurPtr = pStandingWinChainHead->nextPt;
		while(CurPtr != NULL)
		{
			if(CurPtr->hwnd == hwnd)
			{
				PrePtr->nextPt = CurPtr->nextPt;
				delete CurPtr;
				DoneCode = DEL_IN_STANDING_CHAIN;
				break;
			}
			else
			{
				PrePtr = CurPtr;
				CurPtr = CurPtr->nextPt;
			}
		}

		//如果被删除的是最后一个节点,则将指针pStandingWinChainLast
		//改指向前一个节点
		if(CurPtr==pStandingWinChainLast)
			pStandingWinChainLast=PrePtr;
	}
	
	return DoneCode;
}

CMagneticClass::DeleteTheChain(CMagneticClass::WinInfoStrt* pchainHeadPtr)
{
	WinInfoStrt *TempchainPt, *CurchainPt;

	CurchainPt = pchainHeadPtr->nextPt;
	while(CurchainPt != NULL)
	{
		TempchainPt= CurchainPt;
		CurchainPt = CurchainPt->nextPt;
		delete TempchainPt;
	}
	pchainHeadPtr->nextPt = NULL;
}

//此函数将源链表中的所有节点复制到目标链表中
CMagneticClass::CopyChain(/*HWND hwnd,*/ CMagneticClass::WinInfoStrt* SourceChainHead, CMagneticClass::WinInfoStrt* TargetChainLast)
{
	WinInfoStrt*  CurSourcePt = SourceChainHead->nextPt;
	while(CurSourcePt != NULL)
	{
	//	if(CurSourcePt->hwnd != hwnd)
	//	{
			TargetChainLast->nextPt = new WinInfoStrt;
			TargetChainLast			= TargetChainLast->nextPt;
			*TargetChainLast		= *CurSourcePt;
			
	//	}
		CurSourcePt = CurSourcePt->nextPt;
	}

	TargetChainLast->nextPt	= NULL;
}

CMagneticClass::CutPasteStuckChildWindow(CMagneticClass::WinInfoStrt *pCurMovingWinPtr)
{
	WinInfoStrt *PrePtr, *CurPtr;
	PrePtr = pStandingWinChainHead;
	CurPtr = pStandingWinChainHead->nextPt;
	while(CurPtr != NULL)
	{
	/*	if(
			abs(pCurMovingWinPtr->rc.bottom - CurPtr->rc.bottom)<MagneticDistance ||
			abs(pCurMovingWinPtr->rc.bottom - CurPtr->rc.top)<MagneticDistance    ||
			abs(pCurMovingWinPtr->rc.top	- CurPtr->rc.bottom)<MagneticDistance ||
			abs(pCurMovingWinPtr->rc.top	- CurPtr->rc.top)<MagneticDistance    ||
			abs(pCurMovingWinPtr->rc.left	- CurPtr->rc.left)<MagneticDistance   ||
			abs(pCurMovingWinPtr->rc.left   - CurPtr->rc.right)<MagneticDistance  ||
			abs(pCurMovingWinPtr->rc.right  - CurPtr->rc.left)<MagneticDistance   ||
			abs(pCurMovingWinPtr->rc.right  - CurPtr->rc.right)<MagneticDistance
		  )
	*/
		if(
			(pCurMovingWinPtr->rc.bottom == CurPtr->rc.bottom) ||
			(pCurMovingWinPtr->rc.bottom == CurPtr->rc.top)    ||
			(pCurMovingWinPtr->rc.top	== CurPtr->rc.bottom)  ||
			(pCurMovingWinPtr->rc.top	== CurPtr->rc.top)     ||
			(pCurMovingWinPtr->rc.left	== CurPtr->rc.left)	   ||
			(pCurMovingWinPtr->rc.left   == CurPtr->rc.right)  ||
			(pCurMovingWinPtr->rc.right  == CurPtr->rc.left)   ||
			(pCurMovingWinPtr->rc.right  == CurPtr->rc.right)
		  )
		{
			//剪切掉CurPtr指针所指向的节点
			PrePtr->nextPt = CurPtr->nextPt;

			//然后,将这个被剪切下来的节点粘贴到MovingWindowChain的末尾
			pMovingWinChainLast->nextPt=CurPtr;
			pMovingWinChainLast=CurPtr;
			pMovingWinChainLast->nextPt=NULL;

			//修改CurPtr指针的指向
			CurPtr = PrePtr->nextPt;
		}
		else
		{
			PrePtr = CurPtr;
			CurPtr = CurPtr->nextPt;
		}
		
	}

	//如果pStandingWinChain已空, 及时修改链尾指针
	if(pStandingWinChainHead->nextPt == NULL)
	{
		pStandingWinChainLast = pStandingWinChainHead;
	}

}

CMagneticClass::Add_StuckChildWindowsToMovingWindowChain()
{
	//调用函数CutPasteStuckChildWindow,从pStandingWindowChainHead链中寻找跟主窗体粘在一起的子窗口
	//若找到,就将其从StandingWindowChain中“剪切”掉,并“粘贴”到MovingWindowChain中的末尾
	//剪切再粘贴是很好的技术,省掉了delete和new的操作
	WinInfoStrt* currentPtr;
	currentPtr=pMovingWinChainHead->nextPt;
	//每次循环都用MovingWindowChain中的当前节点跟StandingWindowChain中的每个节点进行比对,
	//如果粘到了一起,就将StandingWindowChain中的节点剪切掉,粘贴到MovingWindowChain中的末尾
	while(currentPtr!=NULL)
	{
		CutPasteStuckChildWindow(currentPtr);
		currentPtr=currentPtr->nextPt;
	}
}

CMagneticClass::FillingMovingAndStandingWindowChain(HWND hwnd)
{
	
	
		UINT rt = DeleteAChildWindowInfo(hwnd);

		//将所有Moving window 中的节点复制到 Standing window 链表中,
		//以保证当前显示的所有窗口都被考虑到.一个当前显示的窗口不在Moving window中,必在Standing window中.
		CopyChain(pMovingWinChainHead, pStandingWinChainLast);

		//将 Moving window 链表清空
		DeleteTheChain(pMovingWinChainHead);
		pMovingWinChainLast = pMovingWinChainHead;
		


	//若是主窗口,则
	if(hwnd == pMainWinInfo->hwnd)
	{
		//把主窗口节点添加到 Moving window 链表中
		pMovingWinChainLast->nextPt = new WinInfoStrt;
		pMovingWinChainLast = pMovingWinChainLast->nextPt;
	   *pMovingWinChainLast = *pMainWinInfo;
		
		//寻找跟主窗口粘在一起的子窗口,也存入MovingWindowChain中
		Add_StuckChildWindowsToMovingWindowChain();
	}
	else  //若拖动的是子窗口,则仅仅把这一个窗口添加到Moving window 链表中
	{
		RECT rc;
		GetWindowRect(hwnd,&rc);
		pMovingWinChainLast->nextPt = new WinInfoStrt;
		pMovingWinChainLast			= pMovingWinChainLast->nextPt;
		pMovingWinChainLast->nextPt = NULL;
		pMovingWinChainLast->hwnd	=hwnd;
		pMovingWinChainLast->rc		= rc;
	}
}

//此函数应该被放到OnLButtonDown消息处理函数中
CMagneticClass::OnLButtonDown_CriticalSession(HWND hwnd,POINT &point)
{
	EnableWindow(hwnd,false);
	EnterCriticalSection(&m_cs);
	m_currentHwnd=hwnd;//保存被鼠标拖动的窗口的句柄到变量m_currentHwnd中,其实,这个值根本就没用,因为每个用来保存moving window的节点中都有窗口对应的句柄
	m_bLeftButtonDown=TRUE;
	GetWindowRect(hwnd,&m_rcClient);
	m_MousePoint=point;
	SetCapture(hwnd);

	//重新获得主窗口和各个可见的子窗口的尺寸
	ReGetTheSizeOfAllWindows();	

	//填充MovingWindowChain和StandingWindowChain这两个链表
	FillingMovingAndStandingWindowChain(hwnd);//Save all Moving Windows into Moving Window Chain and Save All Standing Windows into Standing Window Chain
	LeaveCriticalSection(&m_cs);
	EnableWindow(hwnd,true);
}

CMagneticClass::OnLButtonUp_CriticalSession()
{
	EnableWindow(m_currentHwnd,false);
	EnterCriticalSection(&m_cs);
	m_bLeftButtonDown=FALSE;
	ReleaseCapture();
	LeaveCriticalSection(&m_cs);
	EnableWindow(m_currentHwnd,true);
}

CMagneticClass::OnMouseMove_CriticalSession(POINT &point)
{
	if(m_bLeftButtonDown)
	{
		EnterCriticalSection(&m_cs);
		TRACE("PutThisFunctionInOnMouseMoveFunction\n");
		min_deltaX=800;
		min_deltaY=600;
		//实现磁性移动的代码

		//先求出鼠标移动的偏移量
		offsetX=point.x-m_MousePoint.x;
		offsetY=point.y-m_MousePoint.y;
		
		//先要不考虑磁性作用,求出正常拖动窗体后,各个Moving window的新坐标
		CalculateAllMovingWindowsNewPostion();//用类的private变量offsetX和offsetY来传递偏移量,所以,此函数不带参数

		//求出各个Moving window被拖动后,X轴和Y轴方向的Moving windows与standing windows之间的最小距离。
		Calculate_min_deltaX_and_min_deltaY();//计算deltaX和deltaY的值
//		Calculate_DeltaX_and_DeltaY();

		//如果距离值的绝对值大于有效的磁性距离,则无须再调整所有的Moving窗口的移动距离了。

		//如果X方向的距离值的绝对值小于有效的磁性距离,则
		if( (abs(min_deltaX)<MagneticDistance) && (min_deltaX!=0) )
		{
			//修正X轴方向的偏移量
			ModifyLeftAndRightCoordinatesOfAllMovingWindow(-min_deltaX);
		}

		//如果Y方向的距离值的绝对值小于有效的磁性距离,则
		if( (abs(min_deltaY)<MagneticDistance) && (min_deltaY!=0) )
		{
			//修正Y轴方向的偏移量
			ModifyTopAndBottomCoordinatesOfAllMovingWindow(-min_deltaY);
		}

		Actually_Move_All_Moving_Windows();
		LeaveCriticalSection(&m_cs);
	}
}

CMagneticClass::Actually_Move_All_Moving_Windows()
{
	TRACE("Actually_Move_All_Moving_Windows\n");
	WinInfoStrt* currentPtr;
	currentPtr=pMovingWinChainHead->nextPt;
	while(currentPtr!=NULL)
	{
		MoveWindow( currentPtr->hwnd,
					currentPtr->rc.left,
					currentPtr->rc.top,
					currentPtr->rc.right-currentPtr->rc.left,
					currentPtr->rc.bottom-currentPtr->rc.top,
					true );
	
	/*	SetWindowPos(currentPtr->hwnd, NULL, 
			currentPtr->rc.left,
			currentPtr->rc.top,
			0,0,
			SWP_NOSIZE);
		RedrawWindow(currentPtr->hwnd,NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW);
	*/
		TRACE("MoveWindow\n");
		currentPtr=currentPtr->nextPt;
	}
}

CMagneticClass::ReGetTheSizeOfAllWindows()
{
	RECT rc;
//	WinInfoStrt* TempPtr;
	
	//获得主窗口尺寸
	GetWindowRect(pMainWinInfo->hwnd, &rc);
	pMainWinInfo->rc = rc;

	pMovingWinChainCur = pMovingWinChainHead->nextPt;
	while(pMovingWinChainCur != NULL)
	{
		GetWindowRect(pMovingWinChainCur->hwnd, &rc);
		pMovingWinChainCur->rc = rc;
		pMovingWinChainCur = pMovingWinChainCur->nextPt;
	}

	pStandingWinChainCur = pStandingWinChainHead->nextPt;
	while(pStandingWinChainCur != NULL)
	{
		GetWindowRect(pStandingWinChainCur->hwnd, &rc);
		pStandingWinChainCur->rc = rc;
		pStandingWinChainCur = pStandingWinChainCur->nextPt;
	}
}

CMagneticClass::ModifyLeftAndRightCoordinatesOfAllMovingWindow(int deltaX)
{
	WinInfoStrt* currentPtr;
	currentPtr=pMovingWinChainHead->nextPt;

	//需要先检验一下会不会把主窗口吸到屏幕里面出不来,如果不会的,才可以修改
	if(
		(currentPtr->rc.left+deltaX < SCREENX)&&
		(currentPtr->rc.right+deltaX > 0)
	  )
	{
		while(currentPtr!=NULL)
		{
			currentPtr->rc.left	 +=deltaX;
			currentPtr->rc.right +=deltaX;
			currentPtr=currentPtr->nextPt;
		}
	}
}

CMagneticClass::ModifyTopAndBottomCoordinatesOfAllMovingWindow(int deltaY)
{
	WinInfoStrt* currentPtr;
	currentPtr=pMovingWinChainHead->nextPt;

	//需要先检验一下会不会把主窗口吸到屏幕里面出不来,如果不会的,就修改
	if(
		(currentPtr->rc.top+deltaY < SCREENY)&&
		(currentPtr->rc.bottom+deltaY > 0)
	  )
	{
		while(currentPtr!=NULL)
		{
			currentPtr->rc.top		+=deltaY;
			currentPtr->rc.bottom	+=deltaY;
			currentPtr=currentPtr->nextPt;
		}
	}
}

CMagneticClass::CalculateAllMovingWindowsNewPostion()
{
	WinInfoStrt* currentPtr;
	currentPtr=pMovingWinChainHead->nextPt;
	while(currentPtr!=NULL)
	{
		currentPtr->rc.left		+=offsetX;
		currentPtr->rc.right	+=offsetX;
		currentPtr->rc.top		+=offsetY;
		currentPtr->rc.bottom	+=offsetY;
		currentPtr=currentPtr->nextPt;
	}
}

//实现磁性效应的最关键的一个函数!!!
//要用两层嵌套的循环处理,外层循环是Moving Window,内层循环是Standing Window

CMagneticClass::Calculate_min_deltaX_and_min_deltaY()
{
	WinInfoStrt *currentPtr,*CurStandingPtr;
	int temp1;
	//先计算Y轴方向的距离,寻找最小的距离
	currentPtr=pMovingWinChainHead->nextPt;
	while(currentPtr!=NULL)
	{
		CurStandingPtr=pStandingWinChainHead->nextPt;
		while(CurStandingPtr!=NULL)
		{
			//先计算Moving Window的横线 和 Standing Window的横线,是否进入了磁性效应的距离
			//公式是:((x1L-D<x2L<x1R+D)||(x1L-D<x2R<x1R+D))
			if(
			    (
				 ((CurStandingPtr->rc.left-MagneticDistance)<currentPtr->rc.left)&&
				 (currentPtr->rc.left<(CurStandingPtr->rc.right+MagneticDistance))
				)||
			    (
				 ((CurStandingPtr->rc.left-MagneticDistance)<currentPtr->rc.right)&&
				 (currentPtr->rc.right<(CurStandingPtr->rc.right+MagneticDistance))
				)
			  )
			{
				//计算公式是:|y2-y1|<D
				//top and top
				temp1=currentPtr->rc.top-CurStandingPtr->rc.top;
				if(abs(temp1)<MagneticDistance)
				{
					min_deltaY=temp1;
				}

				//top and bottom
				temp1=currentPtr->rc.top-CurStandingPtr->rc.bottom;
				if(abs(temp1)<MagneticDistance)
				{
					min_deltaY=temp1;
				}

				//bottom and top
				temp1=currentPtr->rc.bottom-CurStandingPtr->rc.top;
				if(abs(temp1)<MagneticDistance)
				{
					min_deltaY=temp1;
				}

				//bottom and bottom
				temp1=currentPtr->rc.bottom-CurStandingPtr->rc.bottom;
				if(abs(temp1)<MagneticDistance)
				{
					min_deltaY=temp1;
				}
			}

			CurStandingPtr=CurStandingPtr->nextPt;
		}

		currentPtr=currentPtr->nextPt;
	}


	//再计算X轴方向的距离,寻找最小的距离
	currentPtr=pMovingWinChainHead->nextPt;
	while(currentPtr!=NULL)
	{
		CurStandingPtr=pStandingWinChainHead->nextPt;
		while(CurStandingPtr!=NULL)
		{
			//先计算Moving Window的横线 和 Standing Window的横线,是否进入了磁性效应的距离
			//公式是:((y1Top-D<y2Top<y1Bottom+D)||(y1Top-D<y2Bottom<y1Bottom+D))
			if(
			    (
				 ((CurStandingPtr->rc.top-MagneticDistance)<currentPtr->rc.top)&&
				 (currentPtr->rc.top<(CurStandingPtr->rc.bottom+MagneticDistance))
				)||
			    (
				 ((CurStandingPtr->rc.top-MagneticDistance)<currentPtr->rc.bottom)&&
				 (currentPtr->rc.bottom<(CurStandingPtr->rc.bottom+MagneticDistance))
				)
			  )
			{
				//计算公式是:|y2-y1|<D
				//left and left
				temp1=currentPtr->rc.left-CurStandingPtr->rc.left;
				if(abs(temp1)<MagneticDistance)
				{
					min_deltaX=temp1;
				}

				//left and right
				temp1=currentPtr->rc.left-CurStandingPtr->rc.right;
				if(abs(temp1)<MagneticDistance)
				{
					min_deltaX=temp1;
				}

				//right and left
				temp1=currentPtr->rc.right-CurStandingPtr->rc.left;
				if(abs(temp1)<MagneticDistance)
				{
					min_deltaX=temp1;
				}

				//right and right
				temp1=currentPtr->rc.right-CurStandingPtr->rc.right;
				if(abs(temp1)<MagneticDistance)
				{
					min_deltaX=temp1;
				}
			}

			CurStandingPtr=CurStandingPtr->nextPt;
		}

		currentPtr=currentPtr->nextPt;
	}
}
/////////////////////////////////////////////////////////////////////////
CMagneticClass MagneticObj;		//全局变量,供其他窗口类引用实现磁性

void CMagneticClass::Calculate_DeltaX_and_DeltaY()
{
	WinInfoStrt *currentPtr, *curStandingPtr;
	currentPtr = pMovingWinChainHead->nextPt;
	int dist = 65536;

	//计算X轴方向的距离
	while(currentPtr != NULL)
	{
		curStandingPtr = pStandingWinChainHead->nextPt;
		while(curStandingPtr != NULL)
		{
			int TwoWidth = (currentPtr->rc.right - currentPtr->rc.left)
					+ (curStandingPtr->rc.right - curStandingPtr->rc.left);
			int TwoHeight= (currentPtr->rc.bottom - currentPtr->rc.top)
					+ (curStandingPtr->rc.bottom - curStandingPtr->rc.top);
			//left and right
			if((currentPtr->rc.right - curStandingPtr->rc.left < TwoWidth + MagneticDistance)
				&& (currentPtr->rc.right > curStandingPtr->rc.right))
			{
			    dist = currentPtr->rc.left - curStandingPtr->rc.right;
				if(abs(dist) < MagneticDistance)
				{
					min_deltaX = dist;
				}
			}

			//right and left
			if((curStandingPtr->rc.right - currentPtr->rc.left < TwoWidth + MagneticDistance)
				&& (curStandingPtr->rc.right > currentPtr->rc.right))
			{
				dist = curStandingPtr->rc.left - currentPtr->rc.right;
				if(abs(dist) < MagneticDistance)
				{
					min_deltaX = dist;
				} 
			}

			//top and bottom
			if((currentPtr->rc.bottom - curStandingPtr->rc.top < TwoHeight+MagneticDistance)
				&& (currentPtr->rc.bottom > curStandingPtr->rc.bottom))
			{
				dist = currentPtr->rc.top - curStandingPtr->rc.bottom;
				if(abs(dist) < MagneticDistance)
				{
					min_deltaY = dist;
				} 
			}

			//bottom and top
			if((curStandingPtr->rc.bottom - currentPtr->rc.top < TwoHeight+MagneticDistance)
				&& (curStandingPtr->rc.bottom > currentPtr->rc.bottom))
			{
				dist = curStandingPtr->rc.top - currentPtr->rc.bottom;
				if(abs(dist) < MagneticDistance)
				{
					min_deltaY = dist;
				} 
			}

			curStandingPtr = curStandingPtr->nextPt;

		}

		currentPtr = currentPtr->nextPt;
	}
}